/*
 * MPEGFeature.h
 *        -- feature of MPEG file in compress domain
 *
 * Author: Qiu Shuang
 * Date: April 11th, 2011
 */

#ifndef MPEGFEATURE_H
#define MPEGFEATURE_H

#include "metadata.h"

#define MASK_1      0x01010101
#define MASK_2      0x00110011
#define MASK_4      0x00001111

#define HAMMING_WEIGHT(c, step, mask)     (((c)&(mask))+(((c)>>(step))&(mask)))
#define BITS_TO_BYTES(bits)     (((bits)/BITS_PER_BYTE) + !!((bits)%BITS_PER_BYTE))
#define POS_IN_BITS(bytes, offset)        ((bytes)*BITS_PER_BYTE + (offset))

/* class forward declaration */
class MPEGFile;
class MPEGGranule;

/* define data structure holding granule data */
typedef struct {
    double channel[CHANNEL][ALIGNED_SAMPLES];
} GranuleData, *pGranuleData;

/* define data structure holding features */
typedef struct {
    double subband[DIVIDED_BANDS + 1][CHANNEL];      /* 10 cells, 0-8 for subband info, 9 for the sum */
} GranuleFeature, *pGranuleFeature;

const int DIVIDED_SUBBAND[DIVIDED_BANDS + 1] = {0, 4, 8, 12, 16, 22, 30, 40, 52, 66};

class MPEGFeature{
public:
    /* constructor, take a parsed MPEG file as input */
    MPEGFeature(MPEGFile *dataSource);

    /* destructor */
    ~MPEGFeature();

    /* group granule into block, size indicating number of granules in block */
    void block(int size);

    /* compute entropy feature */
    void extractFeature();

    /* entropy length in bits */
    int length();

    /* get encoded entropy */
    unsigned char *getFeature();

    /* fuzzy match a short bit pattern in a long one, if bit error rate is under threshold */
    /* return bits mis-matched */
    int search(MPEGFeature *shortPattern, double threshold);

private:
    /* align frequency between long and short window */
    /* to long window, mean of three consecutive samples are computed */
    /* as to short window, mean of three consecutive window are computed */
    void alignFrequency();

    /* find in specified data array */
    int internal_search(unsigned char *data, int start, int length);

    /* process original data granule by granule */
    void preprocessFrame(MPEGFrameData *frame);

    int _feature_length;            /* number of bits in the feature */
    int _granules;                  /* number of granules processed */
    int _blocks;                    /* number of blocks */
    unsigned char *_feature;        /* feature storage */
    MPEGFile *_content;             /* parsed data source */
    pGranuleData _data;             /* data to be manipulated */
    pGranuleFeature _features;     /* feature for the whole file */
};

inline int MPEGFeature::length(){
    return _feature_length;
}

inline unsigned char *MPEGFeature::getFeature(){
    return _feature;
}

#endif